﻿Imports Kairyu.DCEngine
Imports System.Reflection
Imports System.Text
Imports System.Threading.Tasks

''' <summary>
''' テーブルマップ
''' </summary>
''' <remarks></remarks>
Public MustInherit Class TableMap

    ''' <summary>
    ''' 階層レベル
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Level As Integer

    Private _index As Integer
    ''' <summary>
    ''' テーブルインデックス
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Index As Integer
        Get
            Return _index
        End Get
        Friend Set(value As Integer)
            _index = value
            Me.AliasName = "T" & value
        End Set
    End Property

    Private _aliasName As String
    ''' <summary>
    ''' 別名
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property AliasName As String
        Get
            Return _aliasName
        End Get
        Private Set(value As String)
            _aliasName = value
        End Set
    End Property

    ''' <summary>
    ''' エンティティ定義
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Definition As EntityDefinition

    Private _relations As New List(Of RelatedTableMap)
    ''' <summary>
    ''' 結合テーブルマップ
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Relations As IList(Of RelatedTableMap)
        Get
            Return _relations
        End Get
    End Property

    Private _columns As New List(Of ColumnMap)
    ''' <summary>
    ''' 列マップ
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Columns As IList(Of ColumnMap)
        Get
            Return _columns
        End Get
    End Property

    ''' <summary>
    ''' JOINテキストに変換します
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Protected Function ToJoinString() As String
        Dim jsql As New StringBuilder

        For Each relmap In Me.Relations
            jsql.AppendDelimiter(ControlChars.NewLine)

            Dim s As New StringBuilder
            Dim props = relmap.RelatedProperties

            For Each item In props
                s.AppendDelimiter(" AND ")
                s.AppendFormat("T{0}.{1}", Me.Index, item.LiteralName)
                s.Append(" = ")
                s.AppendFormat("T{0}.{1}", relmap.Index, item.UpperProperty.LiteralName)
            Next

            If relmap.IsNullable Then
                jsql.AppendFormat("LEFT JOIN {0} {1} ON {2}", relmap.Definition.EntityName, relmap.AliasName, s.ToString)
            Else
                jsql.AppendFormat("INNER JOIN {0} {1} ON {2}", relmap.Definition.EntityName, relmap.AliasName, s.ToString)
            End If


            If relmap.Relations.Any = False Then Continue For
            jsql.AppendDelimiter(ControlChars.NewLine)
            jsql.Append(relmap.ToJoinString())
        Next

        Return jsql.ToString
    End Function

    ''' <summary>
    ''' 列テキストに変換します
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Protected Function ToColumnString() As String
        Dim s As New StringBuilder

        For Each item In (From el In Me.Columns Where el.IsRelated = False)
            s.AppendDelimiter(", ")
            s.Append(item.ToColumnString)
        Next
        For Each item In Me.Relations
            Dim rs As String = item.ToColumnString()
            If String.IsNullOrEmpty(rs) = False Then
                s.AppendDelimiter(", ")
                s.Append(rs)
            End If
        Next

        Return s.ToString
    End Function

    ' ''' <summary>
    ' ''' 主キー列マップを取得します
    ' ''' </summary>
    ' ''' <returns></returns>
    ' ''' <remarks></remarks>
    'Friend Function GetKeyColumnMaps() As IEnumerable(Of ColumnMap)
    '    Return (From el In Me.Columns Where el.LiteralProperty.IsKey)
    'End Function

    ''' <summary>
    ''' マッピングを実行します
    ''' </summary>
    ''' <param name="instance"></param>
    ''' <param name="row"></param>
    ''' <remarks></remarks>
    Friend Sub ExecuteMapping(instance As Object, row As Dictionary(Of String, Object))
        'マッピング
        For Each item In (From el In Me.Columns Where el.IsRelated = False).AsParallel
            Dim val = row(item.AliasName)
            item.LiteralProperty.SetLiteralValue(instance, val)
        Next

        '既定カスケード
        For Each item In (From el In Me.Relations Where el.RelationType = RelationTypes.Base)
            item.ExecuteMapping(instance, row)
        Next

        '上層カスケード
        For Each item In (From el In Me.Relations Where el.RelationType = RelationTypes.Upper)
            Dim upperInstance = item.GetInstance(instance)
            If upperInstance Is Nothing Then Continue For

            item.ExecuteMapping(upperInstance, row)
        Next
    End Sub

    ''' <summary>
    ''' ルートテーブルマップかどうかを示します
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overridable ReadOnly Property IsRoot As Boolean
        Get
            Return False
        End Get
    End Property

End Class